package edu.pku.sei.transformation.editor.parser.texttemplate.equivalence;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import edu.pku.sei.transformation.editor.parser.texttemplate.TemplateParser;
import edu.pku.sei.transformation.editor.parser.texttemplate.element.ElementEdge;
import edu.pku.sei.transformation.editor.parser.texttemplate.element.TextElementRegister;

public class EquivalenceElementsSorter {
	Set<EquivalenceNode> topnodes = new HashSet<EquivalenceNode>();
	
	public static void main(String[] args) {
		TemplateParser parser = new TemplateParser();
		TextElementRegister r1 = parser.parse("[a][b/][c/][/a]", false);
		EquivalenceNode result = new EquivalenceNode(r1);
		TextElementRegister r2 = parser.parse("[a][d/][b/][/a]", false);
		EquivalenceNode result2 = new EquivalenceNode(r2);	
		
		EquivalenceElementsSorter sorter = new EquivalenceElementsSorter();
		sorter.addNodes(result);
		sorter.addNodes(result2);
		result.outgoings.iterator().next().target.merge((EquivalenceNode)result2.outgoings.iterator().next().target);
		sorter.sort();
		System.out.println(result.toString());
		System.out.println();
		System.out.println(r1);
		System.out.println();
		System.out.println(r2);
	}

	public void addNodes(EquivalenceNode root) {
		topnodes.add(root);
	}
	
	private void calculateWeight(Set<EquivalenceNode> nodes) {
		ArrayList<EquivalenceNode> list = new ArrayList<EquivalenceNode>();
		list.addAll(nodes);
		for (int i = 0; i<list.size(); i++) {
			EquivalenceNode node = list.get(i);
			
			if (!node.isVisited) {
				for (EquivalenceLink link : node.outgoings) {
					calculateWeight(link);
					list.add(link.target);
				}
			}
		}
	}
	
	private void calculateWeight(EquivalenceLink link) {
		if (link.isVisited) {
			return;
		}
		System.out.println("\n"+link.hashCode()+" "+link.target.id+"\n");
		int weight = Math.max(1, link.weight);
		link.weight = weight;
		for (EquivalenceLink rightlink : link.rightside) {
			calculateWeight(rightlink, weight+1, link);
		}
		link.isVisited = true;
	}
	
	private void calculateWeight(EquivalenceLink link, int weight, EquivalenceLink source) {
		System.out.println("b:"+link.hashCode()+" "+link.target.id+" "+link.weight);
		if (weight > link.weight) {
			link.weight = weight;
			System.out.println("a:"+link.hashCode()+" "+link.target.id+" "+link.weight);
			if (link.isVisited) {
				for (EquivalenceLink rightlink : link.rightside) {
					if (rightlink != source)
						calculateWeight(rightlink, weight+1, source);
					else
						System.err.println("cycle");
				}
			}
		}
	}
	
	public void sort() {
		calculateWeight(topnodes);
		writeWeight(topnodes);
	}

	private void writeWeight(Set<EquivalenceNode> topNodes) {
		List<EquivalenceNode> nodes = new ArrayList<EquivalenceNode>(topnodes);
		for (int i = 0; i<nodes.size(); i++) {
			EquivalenceNode node = nodes.get(i);
			for (EquivalenceLink link : node.outgoings) {
				for (ElementEdge edge : link.elements) {
					edge.setWeight(link.weight);
				}
				nodes.add(link.target);
			}
		}
		
	}

}
